home *** CD-ROM | disk | FTP | other *** search
- Subject: v21i006: Find files using C expressions, Part01/02
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Kenneth Stauffer <cpsc.UCalgary.CA!stauffer>
- Posting-number: Volume 21, Issue 6
- Archive-name: rh2/part01
-
- Rh was written by Ken Stauffer to make the job of finding files easier by
- allowing the user to enter real C expressions. This notation is much
- easier to master than the notation used by the find(1) command, because
- most Unix users already know C. In addition to being easier to use than
- find(1), rh expressions can be used to select the desired files.
-
- This version provides a fairly powerful mini-language for writing search
- predicates in. It's not unlike the "tw" file walker presented at the
- Baltimore 89 Usenix.
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 1 (of 2)."
- # Contents: MANIFEST Makefile README glob_match.c rh.c rh.h rh.man
- # rhcmds.c rhdata.c rhdir.c rhrc
- # Wrapped by rsalz@litchi.bbn.com on Wed Feb 7 15:35:29 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'MANIFEST' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'MANIFEST'\"
- else
- echo shar: Extracting \"'MANIFEST'\" \(0 characters\)
- sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
- END_OF_FILE
- if test 0 -ne `wc -c <'MANIFEST'`; then
- echo shar: \"'MANIFEST'\" unpacked with wrong size!
- fi
- # end of 'MANIFEST'
- fi
- if test -f 'Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile'\"
- else
- echo shar: Extracting \"'Makefile'\" \(1127 characters\)
- sed "s/^X//" >'Makefile' <<'END_OF_FILE'
- X#
- X# rh:
- X# >>>> VERSION: 2 <<<<
- X# Written by: Ken Stauffer
- X#
- X# Place one of the following -D's onto the end of
- X# the definition of CFLAGS.
- X#
- X# -DSYSV
- X# - System V/III like OS (including Xenix)
- X#
- X# -DBSD
- X# - BSD like OS (including SunOS)
- X#
- X# Also, place one of the following -D's onto the end of
- X# the definition of CFLAGS if you have an operating system
- X# in the specified subclass of the classes listed above.
- X#
- X# -DSUNOS_4
- X# - SunOS 4.x (subclass of BSD)
- X#
- X# -DSYSVR3
- X# - System V Release 3.x (subclass of SYSV)
- X#
- X# getopt.c uses void, so some systems may also need
- X# -Dvoid=int
- X#
- X
- XCFLAGS= -DBSD -DSUNOS_4 -O
- X
- XOBJS= rhcmds.o rh.o rhparse.o rhdir.o rhdata.o getopt.o glob_match.o
- X
- Xrh: $(OBJS)
- X cc $(CFLAGS) -o rh $(OBJS)
- X
- Xrhdir.o: rhdir.c rh.h
- X cc $(CFLAGS) -c rhdir.c
- X
- Xrh.o: rh.c rh.h
- X cc $(CFLAGS) -c rh.c
- X
- Xrhcmds.o: rhcmds.c rh.h
- X cc $(CFLAGS) -c rhcmds.c
- X
- Xrhparse.o: rhparse.c rh.h
- X cc $(CFLAGS) -c rhparse.c
- X
- Xrhdata.o: rhdata.c rh.h
- X cc $(CFLAGS) -c rhdata.c
- X
- Xgetopt.o: getopt.c
- X cc $(CFLAGS) -Dvoid=int -c getopt.c
- X
- Xglob_match.o: glob_match.c
- X cc $(CFLAGS) -Dvoid=int -c glob_match.c
- X
- Xclean:
- X rm -f rh core $(OBJS)
- END_OF_FILE
- if test 1127 -ne `wc -c <'Makefile'`; then
- echo shar: \"'Makefile'\" unpacked with wrong size!
- fi
- # end of 'Makefile'
- fi
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(3646 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- X
- X >>>> V E R S I O N 2 <<<<
- X
- XINTRODUCTION:
- XRh was written by Ken Stauffer to make the
- Xjob of finding files easier by allowing the
- Xuser to enter real C expressions. This notation is
- Xmuch easier to master than the notation used by the
- Xfind(1) command, because most Unix users
- Xalready know C. In addition to being easier to use
- Xthan find(1), rh expressions can be used to select
- Xthe desired files.
- X
- XCREDITS:
- X Guy Harris
- X - Corrected many portability problems.
- X David MacKenzie
- X - Manual revisions. Added getopt and regular expressions.
- X Norm Hutchinson
- X - Fixed ungetit().
- X
- XCOMPILING:
- XTo make rh work on your system, you will need to change
- Xsome -D options in the Makefile. Define ONE of the
- Xfollowing in the definition of CFLAGS:
- X
- X -DBSD - This would be used for most BSD systems.
- X -DSYSV - System V systems.
- X
- XAlso define one of the following:
- X
- X -DSUNOS_4 - SunOS 4.x (subclass of BSD)
- X -DSYSVR3 - System V Release 3.x (subclass of SYSV)
- X
- XIn addition to the C source there is also a file called rh.man.
- XThis is a nroff file and can be created by a command like:
- X
- X nroff -man rh.man > rh.cat
- X
- XThe resultant file (rh.cat) is sutable for general viewing.
- X
- XRUNNING:
- XThere is a file called rhrc. This file contains some
- Xexamples of things that can go into a $HOME/.rhrc file.
- XIf the file "rhrc" is moved to your home directory and renamed
- Xto ".rhrc" then a command like:
- X
- X % rh -l -e writable
- X
- XWill do a search of the current directory, executing the function
- X"writable()", which finds files that other people have write access to.
- X
- XOnce rh is made, you can do what you want with it. A good test to
- Xsee if it is working is to do:
- X
- X % rh -vle 1 /
- X
- XThis will find all files that makes the constant expression '1' true.
- XSo if your root, all the files on the system will be found.
- X
- XPORTABILITY:
- XThe file rhdir.c contains code that does directory reading.
- XThis is most likely where problems will occur. These differences
- Xhave been taken into account for most versions of unix
- Xand will hopefully work on your system.
- XSo far 'rh' works on:
- X SCO XENIX, BSD 4.3, and SUNOS 4.0
- X
- XGRAMMER:
- XThe following is the grammer that describes the input language
- Xrecognized by rh:
- X
- X <program> ==> <function list> <expression> EOF
- X | <function list> <expression> ;
- X
- X <function list> ==> <function>
- X | <function list> <function>
- X | /* empty */
- X
- X <function> ==> <function heading> { RETURN <expression> ; }
- X
- X <function heading> ==> IDENTIFIER
- X | IDENTIFIER ( )
- X | IDENTIFIER ( <idlist> )
- X
- X <idlist> ==> IDENTIFIER <idtail>
- X <idtail> ==> , <idlist>
- X | /* empty */
- X
- X <expression> ==> <expr0> ? <expression> : <expression>
- X
- X <expr0> ==> <expr1> || <expr1>
- X
- X <expr1> ==> <expr2> && <expr2>
- X
- X <expr2> ==> <expr3> | <expr3>
- X
- X <expr3> ==> <expr4> ^ <expr4>
- X
- X <expr4> ==> <expr5> & <expr5>
- X
- X <expr5> ==> <expr6> == <expr6>
- X | <expr6> != <expr6>
- X
- X <expr6> ==> <expr7> < <expr7>
- X | <expr7> > <expr7>
- X | <expr7> <= <expr7>
- X | <expr7> >= <expr7>
- X
- X <expr7> ==> <expr8> >> <expr8>
- X | <expr8> << <expr8>
- X
- X <expr8> ==> <expr9> + <expr9>
- X | <expr9> - <expr9>
- X
- X <expr9> ==> <expr10> * <expr10>
- X | <expr10> / <expr10>
- X | <expr10> % <expr10>
- X
- X <expr10> ==> ~ <expr10>
- X | ! <expr10>
- X | - <expr10>
- X | <factor>
- X
- X <factor> ==> ( <expression> )
- X | NUMBER
- X | <function call>
- X | IDENTIFIER
- X | [ <date spec> ]
- X | STRING
- X
- X <function call> ==> IDENTIFIER
- X | IDENTIFIER ( <exprlist> )
- X | IDENTIFIER ( )
- X
- X <exprlist> ==> <expression> <exprtail>
- X <exprtail> ==> , <exprlist>
- X | /* empty */
- X
- X <datespec> ==> NUMBER / NUMBER / NUMBER
- X
- X--------------------------------------------------------------------
- XKen Stauffer.
- Xroot@sixk
- END_OF_FILE
- if test 3646 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'glob_match.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'glob_match.c'\"
- else
- echo shar: Extracting \"'glob_match.c'\" \(7660 characters\)
- sed "s/^X//" >'glob_match.c' <<'END_OF_FILE'
- X/* File-name wildcard pattern matching for GNU.
- X Copyright (C) 1985, 1988 Free Software Foundation, Inc.
- X
- X NO WARRANTY
- X
- X BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
- XNO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
- XWHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
- XRICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
- XWITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
- XBUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- XFITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
- XAND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
- XDEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
- XCORRECTION.
- X
- X IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
- XSTALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
- XWHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
- XLIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
- XOTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
- XUSE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
- XDATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
- XA FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
- XPROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
- XDAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
- X
- X GENERAL PUBLIC LICENSE TO COPY
- X
- X 1. You may copy and distribute verbatim copies of this source file
- Xas you receive it, in any medium, provided that you conspicuously and
- Xappropriately publish on each copy a valid copyright notice "Copyright
- X(C) 1988 Free Software Foundation, Inc."; and include following the
- Xcopyright notice a verbatim copy of the above disclaimer of warranty
- Xand of this License.
- X
- X 2. You may modify your copy or copies of this source file or
- Xany portion of it, and copy and distribute such modifications under
- Xthe terms of Paragraph 1 above, provided that you also do the following:
- X
- X a) cause the modified files to carry prominent notices stating
- X that you changed the files and the date of any change; and
- X
- X b) cause the whole of any work that you distribute or publish,
- X that in whole or in part contains or is a derivative of this
- X program or any part thereof, to be licensed at no charge to all
- X third parties on terms identical to those contained in this
- X License Agreement (except that you may choose to grant more extensive
- X warranty protection to some or all third parties, at your option).
- X
- X c) You may charge a distribution fee for the physical act of
- X transferring a copy, and you may at your option offer warranty
- X protection in exchange for a fee.
- X
- XMere aggregation of another unrelated program with this program (or its
- Xderivative) on a volume of a storage or distribution medium does not bring
- Xthe other program under the scope of these terms.
- X
- X 3. You may copy and distribute this program (or a portion or derivative
- Xof it, under Paragraph 2) in object code or executable form under the terms
- Xof Paragraphs 1 and 2 above provided that you also do one of the following:
- X
- X a) accompany it with the complete corresponding machine-readable
- X source code, which must be distributed under the terms of
- X Paragraphs 1 and 2 above; or,
- X
- X b) accompany it with a written offer, valid for at least three
- X years, to give any third party free (except for a nominal
- X shipping charge) a complete machine-readable copy of the
- X corresponding source code, to be distributed under the terms of
- X Paragraphs 1 and 2 above; or,
- X
- X c) accompany it with the information you received as to where the
- X corresponding source code may be obtained. (This alternative is
- X allowed only for noncommercial distribution and only if you
- X received the program in object code or executable form alone.)
- X
- XFor an executable file, complete source code means all the source code for
- Xall modules it contains; but, as a special exception, it need not include
- Xsource code for modules which are standard libraries that accompany the
- Xoperating system on which the executable file runs.
- X
- X 4. You may not copy, sublicense, distribute or transfer this program
- Xexcept as expressly provided under this License Agreement. Any attempt
- Xotherwise to copy, sublicense, distribute or transfer this program is void and
- Xyour rights to use the program under this License agreement shall be
- Xautomatically terminated. However, parties who have received computer
- Xsoftware programs from you with this License Agreement will not have
- Xtheir licenses terminated so long as such parties remain in full compliance.
- X
- X
- XIn other words, you are welcome to use, share and improve this program.
- XYou are forbidden to forbid anyone else to use, share and improve
- Xwhat you give them. Help stamp out software-hoarding! */
- X
- X/* Match the pattern PATTERN against the string TEXT;
- X return 1 if it matches, 0 otherwise.
- X
- X A match means the entire string TEXT is used up in matching.
- X
- X In the pattern string, `*' matches any sequence of characters,
- X `?' matches any character, [SET] matches any character in the specified set,
- X [^SET] matches any character not in the specified set.
- X
- X A set is composed of characters or ranges; a range looks like
- X character hyphen character (as in 0-9 or A-Z).
- X [0-9a-zA-Z_] is the set of characters allowed in C identifiers.
- X Any other character in the pattern must be matched exactly.
- X
- X To suppress the special syntactic significance of any of `[]*?^-\',
- X and match the character exactly, precede it with a `\'.
- X
- X If DOT_SPECIAL is nonzero,
- X `*' and `?' do not match `.' at the beginning of TEXT. */
- X
- Xint
- Xglob_match (pattern, text, dot_special)
- X char *pattern, *text;
- X int dot_special;
- X{
- X register char *p = pattern, *t = text;
- X register char c;
- X
- X while ((c = *p++))
- X {
- X switch (c)
- X {
- X case '?':
- X if (*t == 0 || (dot_special && t == text && *t == '.')) return 0;
- X else ++t;
- X break;
- X
- X case '\\':
- X if (*p++ != *t++) return 0;
- X break;
- X
- X case '*':
- X if (dot_special && t == text && *t == '.')
- X return 0;
- X return star_glob_match (p, t);
- X
- X case '[':
- X {
- X register char c1 = *t++;
- X register int invert = (*p == '^');
- X
- X if (invert) p++;
- X
- X c = *p++;
- X while (1)
- X {
- X register char cstart = c, cend = c;
- X
- X if (c == '\\')
- X {
- X cstart = *p++; cend = cstart;
- X }
- X c = *p++;
- X if (c == '-')
- X { cend = *p++; if (cend == '\\') cend = *p++; c = *p++; }
- X if (c1 >= cstart && c1 <= cend) goto match;
- X if (c == ']')
- X break;
- X }
- X if (!invert) return 0;
- X break;
- X
- X match:
- X /* Skip the rest of the [...] construct that already matched. */
- X while (c != ']')
- X {
- X c = *p++;
- X if (c == '\\') p++;
- X }
- X if (invert) return 0;
- X break;
- X }
- X
- X default:
- X if (c != *t++) return 0;
- X }
- X }
- X
- X if (*t) return 0;
- X return 1;
- X}
- X
- X/* Like glob_match, but match PATTERN against any final segment of TEXT. */
- X
- Xstatic int
- Xstar_glob_match (pattern, text)
- X char *pattern, *text;
- X{
- X register char *p = pattern, *t = text;
- X register char c, c1;
- X
- X while ((c = *p++) == '?' || c == '*')
- X {
- X if (c == '?' && *t++ == 0)
- X return 0;
- X }
- X
- X if (c == 0)
- X return 1;
- X
- X if (c == '\\') c1 = *p;
- X else c1 = c;
- X
- X for (;;)
- X {
- X if ((c == '[' || *t == c1)
- X && glob_match (p - 1, t, 0))
- X return 1;
- X if (*t++ == 0) return 0;
- X }
- X}
- END_OF_FILE
- if test 7660 -ne `wc -c <'glob_match.c'`; then
- echo shar: \"'glob_match.c'\" unpacked with wrong size!
- fi
- # end of 'glob_match.c'
- fi
- if test -f 'rh.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'rh.c'\"
- else
- echo shar: Extracting \"'rh.c'\" \(6063 characters\)
- sed "s/^X//" >'rh.c' <<'END_OF_FILE'
- X
- X/* ----------------------------------------------------------------------
- X * FILE: rh.c
- X * VERSION: 2
- X * Written by: Ken Stauffer
- X *
- X * printhelp(), execute(), exam1(), exam2(), exam3(), main()
- X *
- X *
- X * ---------------------------------------------------------------------- */
- X
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include "rh.h"
- X
- Xstatic char usage[]={
- X"Usage: %s [-vhlr] [ [-e expr] | [-f filename ] ] [-x command ] file ...\n"
- X};
- X
- X/* ----------------------------------------------------------------------
- X * printhelp:
- X * Print out the help screen. The string 's' is argv[0].
- X * Called when the -h option is used.
- X *
- X */
- X
- Xprinthelp(s)
- Xchar *s;
- X{
- X int i;
- X struct symbol *p;
- X
- X printf(usage,s);
- X printf("options:\n");
- X printf("\t-h show this message\n");
- X printf("\t-l long filename output\n");
- X printf("\t-r makes %s non-recursive\n",s);
- X printf("\t-v verbose output\n");
- X printf("\t-e get expression from the command line\n");
- X printf("\t-f get expression from file\n");
- X printf("\t-x execute a unix command for matching files\n\n");
- X
- X printf("\tvalid symbols:\n");
- X for(i=1, p=symbols; p; p=p->next, i++)
- X printf("%12s%s", p->name,
- X ((i-1)%5==4 || !p->next ) ? "\n" : " ");
- X
- X printf("\tC operators:\n");
- X printf("\t! ~ - * / %% + < <= > >= == != & ^ | << >> && || ?:\n");
- X printf("\tspecial operators:\n");
- X printf("\t$username , \"*.c\" , [yyyy/mm/dd]\n\n");
- X}
- X
- X/* ----------------------------------------------------------------------
- X * execute:
- X * Execute the program contained in the StackProgram[]
- X * array. Each element of the StackProgram[] array contains
- X * a pointer to a function.
- X * Programs are NULL terminated.
- X * Returns the result of the expression.
- X *
- X */
- X
- Xexecute()
- X{
- X register long eval;
- X register int (*efunc)();
- X
- X SP=0;
- X for(PC=startPC; (efunc=StackProgram[PC].func) ; PC++) {
- X eval=StackProgram[PC].value;
- X (*efunc)(eval);
- X if( SP >= MEM ) {
- X fprintf(stderr,"stack overflow\n");
- X exit(1);
- X }
- X }
- X return( Stack[0] );
- X}
- X
- X/* ----------------------------------------------------------------------
- X * exam1: exam2: exam3:
- X * One of these functions is called for every file that 'rh' examines.
- X * exam{1,2,3}() first calls execute to see if the
- X * expression is true, it then prints the file if the expression
- X * evaluated to true (non-zero).
- X *
- X */
- X
- X/* print file out by itself */
- Xexam1()
- X{
- X if( execute() ) printf("%s\n",attr.fname);
- X}
- X
- X/* long output of file */
- Xexam2()
- X{
- X if( execute() ) printentry(attr.verbose,attr.buf,attr.fname);
- X}
- X
- X/* do a system(3) call to desired command */
- Xexam3()
- X{
- X char command[ 2048 + 1 ];
- X char *p,*q,*r,*strrchr();
- X int rv;
- X
- X if( execute() ) {
- X p=command;
- X q=attr.command;
- X while( *q ) {
- X if( *q != '%' ) *p++ = *q++;
- X else {
- X q += 1;
- X if( *q == 's' ) {
- X r = attr.fname;
- X while( *p++ = *r++ );
- X p -= 1;
- X } else if( *q == 'S' ) {
- X r = strrchr(attr.fname,'/');
- X r = (r) ? r+1 : attr.fname;
- X while( *p++ = *r++ );
- X p -= 1;
- X } else *p++ = '%';
- X q += 1;
- X }
- X }
- X *p = '\0';
- X rv = system(command);
- X if( attr.verbose ) printf("%s exit(%d)\n",command,rv);
- X }
- X}
- X
- X
- X/* ----------------------------------------------------------------------
- X * main:
- X * parse arguments.
- X * gnu getopt() is used here.
- X * -l, -r, -h, -v options can occur as often as desired.
- X * -f,-x and -e can only occur once and MUST have an argument.
- X *
- X * Read and "compile" the $HOME/.rhrc file, if it exists.
- X * Read and "compile" any -f filename, if present.
- X * Read and "compile" any -e expression, if present.
- X * If after all that no start expression is found then read from
- X * stdin for one.
- X * Perform the recursive hunt on remaining arguments.
- X *
- X */
- X
- Xmain(argc,argv)
- Xint argc;
- Xchar *argv[];
- X{
- X extern int optind;
- X extern char *optarg;
- X char *dashe,*dashf,*strcat(),*getenv(),initfile[ 1024+1 ];
- X int i,r;
- X int dashr,dashh,dashl;
- X int (*examptr)();
- X
- X /* defaults */
- X dashe = NULL; /* -e option */
- X dashl = 0; /* -l */
- X dashf = NULL; /* -f */
- X dashr = 1; /* -r */
- X dashh = 0; /* -h */
- X attr.verbose = 0; /* -v */
- X attr.command = NULL; /* -x */
- X examptr = exam1; /* default output function */
- X
- X while ((i = getopt(argc, argv, "lrhvx:e:f:")) != EOF) {
- X switch( i ) {
- X case 'l': examptr = exam2; dashl = 1; break;
- X case 'r': dashr = 0; break;
- X case 'h': dashh = 1; break;
- X case 'v': attr.verbose = 1; break;
- X case 'x':
- X if( attr.command ) {
- X fprintf(stderr, "%s: too many -x options\n",argv[0]);
- X exit(1);
- X }
- X examptr = exam3;
- X attr.command = optarg;
- X break;
- X case 'e':
- X if( dashe ) {
- X fprintf(stderr, "%s: too many -e options\n",argv[0]);
- X exit(1);
- X }
- X dashe = optarg;
- X break;
- X case 'f':
- X if( dashf ) {
- X fprintf(stderr, "%s: too many -f options\n",argv[0]);
- X exit(1);
- X }
- X dashf = optarg;
- X break;
- X default:
- X fprintf(stderr,"%s: use -h for help\n", argv[0],i);
- X fprintf(stderr,usage, argv[0]);
- X exit(1);
- X }
- X if( attr.command && dashl ) {
- X fprintf(stderr,
- X "%s: cannot have both -x and -l options\n",
- X argv[0]);
- X exit(1);
- X }
- X }
- X
- X PC = 0;
- X startPC = -1;
- X rhinit();
- X if( dashh ) printhelp(argv[0]);
- X
- X expfname = getenv( HOMEENV );
- X if( expfname ) {
- X strcpy(initfile,expfname);
- X expfname = strcat(initfile,RHRC);
- X if( (expfile = fopen(expfname,"r")) != NULL ) {
- X expstr = NULL;
- X program();
- X }
- X }
- X
- X if( dashf ) {
- X expstr = NULL;
- X expfname = dashf;
- X if( (expfile = fopen(expfname,"r")) == NULL ) {
- X fprintf(stderr,"%s: ", argv[0]);
- X perror(expfname);
- X exit(1);
- X }
- X program();
- X }
- X if( dashe ) {
- X expfile = NULL;
- X expstr = dashe;
- X program();
- X }
- X if( startPC == -1 ) {
- X expstr = NULL;
- X expfname = "stdin";
- X expfile = stdin;
- X program();
- X }
- X
- X if( startPC == -1 ) {
- X fprintf(stderr,"%s: no start expression specified\n",
- X argv[0] );
- X exit(1);
- X }
- X rhfinish();
- X
- X if( optind >= argc ) {
- X r=ftrw(".",examptr,(dashr)? DEPTH :1);
- X if(r == -1) perror(".");
- X } else
- X for(; optind<argc; optind++) {
- X r=ftrw(argv[optind],examptr,(dashr)? DEPTH :1);
- X if( r == -1 ) perror(argv[optind]);
- X }
- X exit(0);
- X}
- END_OF_FILE
- if test 6063 -ne `wc -c <'rh.c'`; then
- echo shar: \"'rh.c'\" unpacked with wrong size!
- fi
- # end of 'rh.c'
- fi
- if test -f 'rh.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'rh.h'\"
- else
- echo shar: Extracting \"'rh.h'\" \(3361 characters\)
- sed "s/^X//" >'rh.h' <<'END_OF_FILE'
- X
- X/* ----------------------------------------------------------------------
- X * FILE: rh.h
- X * VERSION: 2
- X * Written by: Ken Stauffer
- X * This header contains the #define's for the tokens.
- X * It also contains structure definitions.
- X *
- X * ---------------------------------------------------------------------- */
- X
- X#include <stdio.h>
- X
- X#define RHRC "/.rhrc" /* start up file */
- X#define RHENV "RH" /* rh environment variable */
- X#define HOMEENV "HOME" /* path to your home directory */
- X
- X/* Definition of returned tokens from the lexical analyzer */
- X
- X#define OR 256 /* || */
- X#define AND 257 /* && */
- X#define LE 258 /* <= */
- X#define GE 259 /* >= */
- X#define NE 260 /* != */
- X#define EQ 261 /* == */
- X#define SHIFTL 262 /* << */
- X#define SHIFTR 263 /* >> */
- X#define NOP 264 /* no-operation */
- X#define NUMBER 265 /* literal numbers and symbolic constants */
- X#define STR 266 /* regular expression strings */
- X#define FIELD 267 /* file fields (size,mode,nlinks) */
- X#define FUNCTION 268 /* user defined function */
- X#define RETURN 269 /* return keyword */
- X#define PARAM 270 /* parameter to functions */
- X#define IDENTIFIER 271
- X
- X#define LENGTH 2000 /* size of stack program */
- X#define MEM 1000 /* size of stack */
- X#define IDLENGTH 20 /* length of an identifier */
- X#define STRLEN 200 /* total chars available for strings */
- X
- X#if BSD
- X#define DEPTH getdtablesize()
- X#define strrchr rindex
- X#ifdef SUNOS_4
- X#define POSIX_DIRECTORY_LIBRARY
- X#endif /* SUNOS_4 */
- X#endif /* BSD */
- X
- X#ifdef SYSV
- X#ifdef SYSVR3
- X#define DEPTH ulimit(4, 0L)
- X#define POSIX_DIRECTORY_LIBRARY
- X#else /* SYSVR3 */
- X/* This value was arbitrarily chosen */
- X#define DEPTH 20
- X#endif /* SYSVR3 */
- X#endif /* SYSV */
- X
- X/*
- X * Structure of a "rh-assembly" instruction.
- X *
- X */
- X
- Xstruct instr {
- X int (*func)();
- X long value;
- X};
- X
- X/*
- X * Structure of a symbol.
- X *
- X */
- X
- Xstruct symbol {
- X char *name;
- X int type;
- X long value;
- X int (*func)();
- X struct symbol *next;
- X};
- X
- X/*
- X * Structure defining the rh runtime environment.
- X *
- X */
- X
- Xstruct runtime {
- X struct stat *buf; /* stat info of current file */
- X char *fname; /* file name of current file */
- X int depth; /* relative depth of current file */
- X int (*func)(); /* examination function */
- X int prune; /* flag to indicate prunning */
- X int verbose; /* used by the (*func)() routine */
- X char *command; /* command to exec for current file */
- X};
- X
- X#ifndef DATA
- X extern struct symbol *symbols;
- X
- X extern struct symbol *tokensym;
- X extern long tokenval;
- X extern long token;
- X
- X extern struct instr StackProgram[];
- X extern int PC;
- X extern int startPC;
- X extern long Stack[];
- X extern int SP;
- X extern int FP; /* frame pointer */
- X
- X extern struct runtime attr;
- X
- X extern char Strbuf[];
- X extern int strfree;
- X
- X extern char *expstr;
- X extern char *expfname;
- X extern FILE *expfile;
- X
- X#endif
- X
- Xextern c_or(), c_and(), c_le(), c_lt(), c_ge(),
- X c_gt(), c_ne(), c_eq(), c_bor(), c_band(),
- X c_bxor(), c_not(), c_plus(), c_mul(), c_minus(),
- X c_div(), c_mod(), c_number(), c_atime(), c_ctime(),
- X c_dev(), c_gid(), c_ino(), c_mode(), c_mtime(),
- X c_nlink(), c_rdev(), c_size(), c_uid(), c_str(),
- X c_bnot(), c_uniminus(), c_lshift(), c_rshift(), c_qm(),
- X c_colon(), c_return(), c_func(), c_param(), c_depth(),
- X c_baselen(), c_pathlen(), c_prune();
- X
- END_OF_FILE
- if test 3361 -ne `wc -c <'rh.h'`; then
- echo shar: \"'rh.h'\" unpacked with wrong size!
- fi
- # end of 'rh.h'
- fi
- if test -f 'rh.man' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'rh.man'\"
- else
- echo shar: Extracting \"'rh.man'\" \(12150 characters\)
- sed "s/^X//" >'rh.man' <<'END_OF_FILE'
- X.TH RH 1L
- X.SH NAME
- Xrh - recursive file locater (rawhide) >> VERSION 2 <<
- X.SH SYNOPSIS
- X.B rh
- X[
- X.B \-vhlr
- X] [
- X.B \-f filename
- X]
- X.br
- X.RS
- X[
- X.B \-e expression
- X] [
- X.B \-x command
- X]
- X.BR file ...
- X.RE
- X.SH DESCRIPTION
- X.I Rh
- Xrecursively searches the file system starting at each given
- X.IR file
- Xfor files that make a C expression true. If no files
- Xare listed, the current working directory is used.
- X.PP
- XExpressions for
- X.I rh
- Xcan come from the command line (with the
- X.I \-e
- Xoption), a file (with the
- X.I \-f
- Xoption), or from the standard input (the default).
- XThe basic form of an
- X.I rh
- Xexpression is a C expression which may optionally define and or call
- Xuser defined functions. These C expressions may contain
- Xconstants, variables, and all the usual C operators.
- X.PP
- X.I Constants
- Xare either numeric or symbolic. Symbolic constants are based
- Xon the constants defined in the file
- X.IR /usr/include/sys/stat.h ;
- Xonly the useful constants are implemented.
- XThe ``S_'' prefix from the symbol name is omitted.
- X(eg. S_IFMT would used as IFMT).
- X.PP
- X.I Variables
- Xare symbols that specify a field in the
- Xstat structure (e.g., st_size, st_mode) or some other attribute of the file.
- XFor each file examined by
- X.IR rh ,
- Xthese internal variables are updated to match the current
- Xfile. For convenience, the ``st_'' prefix is dropped from variable
- Xnames.
- X.PP
- X.I Functions
- Xare a means of associating a C expression with a function name.
- XThis allows complex expressions to be easily composed from simpler ones.
- XThe value
- Xof a function call is the value of the expression represented by the
- Xfunction. For example:
- X.PP
- X.RS 8
- Xfoo(x)
- X.br
- X{
- X.br
- Xreturn( x-1 );
- X.br
- X}
- X.RE
- X.PP
- XIf the above function were given to Rh, it would define a function that could be
- Xused later. If
- X.I foo
- Xwere called with 667, then the value of the call to
- X.I foo
- Xwould be equal to 666.
- X.PP
- X.SH OPTIONS
- X.I Rh
- Xoptions can appear in any order; multiple options can
- Xbe given within the same argument.
- X.TP
- X.I \-r
- XPrevents
- X.I rh
- Xfrom recursively searching for files.
- X.TP
- X.I \-l
- XNormally
- X.I rh
- Xprints each matching filename on a line by itself. The
- X.I \-l
- Xoption causes the matching files' permission modes and sizes
- Xto be displayed as well, in a format similar to that of the
- X.IR ls (1)
- Xcommand.
- X.TP
- X.I \-h
- XCauses
- X.I rh
- Xto display a help message. The message
- Xexplains the command line usage, a list of
- Xavailable constants and variables and a list
- Xof valid operators.
- X.I Rh
- Xthen continues as though the
- X.I \-h
- Xoption were not present.
- X.TP
- X.I \-f filename
- XUses
- X.I filename
- Xas the name of a file containing a
- X.I rh
- Xexpression. Functions may also be defined in this file.
- X.TP
- X.I \-e expression
- XUses
- X.I expression
- Xas the expression
- Xthat will be used for the file search.
- XSince many of the operators are also shell
- Xmeta-characters and since rh expressions may contain
- Xspaces, it is strongly recommended that the
- X.I expression
- Xbe enclosed in single quotes, ''. If both the -e and -f options
- Xoccur together then the -f option is processed FIRST, followed by the
- X-e option. This means that an expression specified with the -e option
- Xmay use functions defined from the
- X.I -f file.
- X.TP
- X.I \-v
- XVerbose. Causes the -l option to output more information and
- Xthe -x option to print out the command executed and the return value.
- X.TP
- X.I \-x command
- XExecute
- X.I command
- Xusing system(3) for each matching file. The string
- X.I command
- Xmay contain a %s which will be substituted with the full path name. A
- X%S (uppercase 'S') will be substituted with the base name. For example,
- Xgiven the file /etc/passwd the values for %s and %S would be:
- X/etc/passwd and passwd, respectively.
- X.SH USAGE
- X.SS "Rh grammer"
- XThis is the grammer that rh will accept.
- X.PP
- X.TP
- X<program> ::=
- X.RS 6
- X <function list> <expression> EOF
- X.br
- X | <function list> <expression> ;
- X.RE
- X.PP
- X.TP
- X<function list> ::=
- X.RS 6
- X <function list> <function>
- X.br
- X | <function>
- X.br
- X | /* empty */
- X.RE
- X.PP
- X.TP
- X<function> ::=
- X.RS 6
- X <function heading> { RETURN <expression> ; }
- X.RE
- X.PP
- X.TP
- X<function heading> ::=
- X.RS 6
- X IDENTIFIER
- X.br
- X | IDENTIFIER ( )
- X.br
- X | IDENTIFIER ( <idlist> )
- X.RE
- X.PP
- X.TP
- X<idlist> ::=
- X.RS 6
- X <idlist> , IDENTIFIER
- X.br
- X | IDENTIFIER
- X.RE
- X.PP
- X.TP
- X<expression> ::=
- X.RS 6
- X <expression> ? <expression> : <expression>
- X.br
- X | <expression> || <expression>
- X.br
- X | <expression> && <expression>
- X.br
- X | <expression> | <expression>
- X.br
- X | <expression> ^ <expression>
- X.br
- X | <expression> & <expression>
- X.br
- X | <expression> == <expression>
- X.br
- X | <expression> != <expression>
- X.br
- X | <expression> < <expression>
- X.br
- X | <expression> > <expression>
- X.br
- X | <expression> <= <expression>
- X.br
- X | <expression> >= <expression>
- X.br
- X | <expression> >> <expression>
- X.br
- X | <expression> << <expression>
- X.br
- X | <expression> + <expression>
- X.br
- X | <expression> - <expression>
- X.br
- X | <expression> * <expression>
- X.br
- X | <expression> / <expression>
- X.br
- X | <expression> % <expression>
- X.br
- X | ~ <expression>
- X.br
- X | ! <expression>
- X.br
- X | - <expression>
- X.br
- X | <factor>
- X.RE
- X.PP
- X.TP
- X<factor> ::=
- X.RS 6
- X ( <expression> )
- X.br
- X | NUMBER
- X.br
- X | <function call>
- X.br
- X | IDENTIFIER
- X.br
- X | [ <date spec> ]
- X.br
- X | STRING
- X.RE
- X.PP
- X.TP
- X<function call> ::=
- X.RS 6
- X IDENTIFIER
- X.br
- X | IDENTIFIER ( <exprlist> )
- X.br
- X | IDENTIFIER ( )
- X.RE
- X.PP
- X.TP
- X<exprlist> ::=
- X.RS 6
- X <exprlist> , <expression>
- X.br
- X | <expression>
- X.RE
- X.PP
- X.TP
- X<datespec> ::=
- X.RS 6
- X NUMBER / NUMBER / NUMBER
- X.RE
- X.PP
- X.SS "Search order:"
- X.I Rh
- Xinitally looks for a
- X.I $HOME/.rhrc
- Xand if it exists it will be read in. Next, any file specified by the
- X.I \-f
- Xoption is read followed by any expression specified with the
- X.I \-e
- Xoption. If after all that, an expression, defined outside of a function,
- Xhas not been encountered then stdin will be read for such an expression.
- XAn error will result if no expression has been encountered.
- X.PP
- XA
- X.I $HOME/.rhrc
- Xwill usually contain function definitions that will be accessable
- Xfor the user when they enter in a search expression.
- X.PP
- X.SS "The valid constants are:"
- X.IP NOW
- XThis constant is set to the current time at the start of
- X.I rh.
- XIt is used to make comparisons with atime, ctime and mtime.
- X.IP days
- XThis is equal to the number of seconds in a day.
- X.IP hours
- XNumber of seconds in an hour.
- X.IP weeks
- XNumber of seconds in a week.
- X.IP "IFBLK IFDIR IFLNK IFMT IFREG IFSOCK ISGID ISUID ISVTX"
- Xsee
- X.IR stat (2)
- Xfor an explanation.
- X.SS "The valid variables are:"
- X.PP
- X.IP depth
- XThis variable is set to the relative depth in the directory search
- Xthat the current file is at.
- X.IP strlen
- XThis is set to the length of the filename. For example strlen
- Xwould be equal to 4 given the file: "/tmp/core" because "core" is
- X4 characters long.
- X.IP prune
- XThis varible always returns 0, but as a side-effect causes the
- Xsearch path to be "cut-short" when evaluated. This can be used to prune the
- Xdirectory search.
- X.I prune
- Xis usually used with the ?: operator to conditionally evaluate the prune
- Xvariable.
- X.IP "atime,ctime,dev,gid,ino,mode,mtime,nlink,rdev,size,uid"
- Xsee
- X.IR stat (2)
- Xfor an explanation.
- X.SS "The valid C operators are:"
- X.PP
- X! ~ - * / % + < <= > >= == != & ^ | << >> && || ?:
- X.PP
- XOperator precedence, associativity and semantics are the same as
- Xin C.
- X.SS "Special operators:"
- X.IP $username
- XThis operator evaluates to the integer user id of
- X.I username.
- XAs a special case the symbol $$ evaluates to the
- Xuid of the user currently running
- X.I rh.
- X.IP """*.c"""
- XThis operator evaluates to true if the current filename matches
- Xthe quoted expression, which is a shell globbing pattern.
- XThe recognized metacharacters are:
- X.RS
- X.IP ``*''
- Xto match any number of characters, including zero (except that, as in
- Xthe shell, it does not match a leading ``.'');
- X.IP ``?''
- Xto match any single character (except for a leading ``.'');
- X.IP ``[SET]''
- Xto match any character in the given set (ranges can be included);
- X.IP ``[^SET]''
- Xto match any character not in the given set;
- X.IP ``\e\e''
- Xto escape the special meaning of any of the above metacharacters.
- X.RE
- X.PP
- XWhen doing comparisons, only the base name is examined, not
- Xleading paths.
- X.IP [yyyy/mm/dd]
- XThe date enclosed in the brackets, ``[]'', will evaluate to a number of
- Xseconds past January 1, 1970, which is
- Xsuitable for comparing with atime, mtime or ctime.
- XThe year cannot be abbreviated to its last two digits.
- X.PP
- XThe special operators
- Xhave higher precedence than the C operators.
- X.SS "Lexical conventions:"
- X.PP
- XNumbers may be entered in octal by preceding them with
- Xa leading zero. Otherwise numbers are taken to be in
- Xdecimal.
- X.PP
- XText enclosed in /* and */ will be ignored. This can be
- Xused for commenting
- X.I rh
- Xexpression files.
- X.PP
- XThe start expression may be terminated by either
- Xa ``;'' or the end of the file or argument.
- X.SH EXAMPLES
- XThe following are examples of
- X.I rh
- Xexpressions.
- X.PP
- X.RS 8
- X(mode & 022) && (uid == $joe );
- X.PP
- X.RE
- XMatches all files that have uid equal to username ``joe'' and
- Xare writable by other people.
- X.PP
- X.RS 8
- X!uid && (mode & ISUID ) &&
- X.br
- X(mode & 02);
- X.PP
- X.RE
- XMatches all files that are owned by root (uid==0) and that
- Xhave set-uid on execution bit set, and are writable.
- X.PP
- X.RS 8
- X(size > 10*1024) && (mode & 0111) &&
- X.br
- X(atime <= NOW-24*3600);
- X.RE
- X.PP
- XFinds all executable files larger than 10K that
- Xhave not been executed in the last 24 hours.
- X.PP
- X.RS 8
- Xsize < ( ("*.c") ? 4096 : 32*1024 );
- X.RE
- X.PP
- XFinds C source files smaller than 4K and
- Xother files smaller than 32K. No other files will match.
- X.PP
- X.RS 8
- X!(size % 1024);
- X.RE
- X.PP
- XMatches files that are a multiple of 1K.
- X.PP
- X.RS 8
- Xmtime >= [1982/3/1] && mtime <= [1982/3/31];
- X.RE
- X.PP
- XFinds files that were modified during March, 1982.
- X.PP
- X.RS 8
- Xstrlen >= 4 && strlen <= 10;
- X.RE
- X.PP
- XThis expression will print files whose filenames are between
- X4 and 10 characters in length.
- X.PP
- X.RS 8
- Xdepth > 3;
- X.RE
- X.PP
- XMatches files that are at a RELATIVE depth of 3 or more.
- X.PP
- X.RS 8
- X( "tmp" || "bin" ) ? prune : "*.c";
- X.RE
- X.PP
- XThis expression does a search for all "*.c" files, however it will
- Xnot look into any directories called "bin" or "tmp". This is because when
- Xsuch a filename is encountered the prune variable is evaluated, causing
- Xfurther searching with the current path to stop. The general form of this
- Xwould be:
- X.PP
- X.RS 8
- X("baddir1" || "baddir2" || ... || "baddirn") ?
- X.br
- X.RS 8
- Xprune : <search expr>;
- X.RE
- X.RE
- X.PP
- X.SH "ADVANCED EXAMPLES"
- XThe following examples show the use of function definitions and other
- Xadvanced features of
- X.I "Rh."
- X Consider:
- X.PP
- X.RS 8
- Xdir()
- X.br
- X{
- X.br
- Xreturn ( (mode & IFMT) == IFDIR );
- X.br
- X}
- X.br
- X.RE
- X.PP
- XThis declares a function that returns true if the current file is a directory
- Xand false otherwise. The function
- X.PP
- X.I dir
- Xnow may be used in other expressions.
- X.PP
- X.RS 8
- Xdir() && !mine();
- X.RE
- X.PP
- XThis matches files that are directories and are not owned by
- Xthe user. This assumes the user has written a mine() function. Since
- X.I dir
- Xand
- X.I mine
- Xtake no arguments they may be called like:
- X.PP
- X.RS 8
- Xdir && !mine;
- X.RE
- X.PP
- XAlso when declaring a function that takes no arguments the parenthesis
- Xmay be omitted. For example:
- X.PP
- X.RS 8
- Xmine
- X.br
- X{
- X.br
- Xreturn uid == $joe;
- X.br
- X}
- X.br
- X.RE
- X.PP
- XThis declares a function mine, that evaluates true when a file
- Xis owned by user name 'joe'. An alternate way to write mine would be:
- X.PP
- X.RS 8
- Xmine(who)
- X.br
- X{
- X.br
- Xreturn uid == who;
- X.br
- X}
- X.br
- X.RE
- X.PP
- XThis would allow mine to be called with an argument, for example:
- X.PP
- X.RS 8
- Xmine( $sue ) || mine( $joe );
- X.RE
- X.PP
- XThis expression is true of any file owned by user name 'sue' or 'joe'.
- XSince the parenthesis are optional for functions that take no
- Xarguments, it would be possible to define functions that can be used
- Xexactly like constants, or handy macros. Suppose the above definition
- Xof
- X.I dir
- Xwas placed in a users
- X.I $HOME/.rhrc
- XThen the command:
- X.PP
- X.RS 8
- Xrh -e dir
- X.RE
- X.PP
- Xwould execute the expression 'dir' which will print out all directories.
- XRh functions can be recursive.
- X.SH "FILES"
- X$HOME/.rhrc
- X.PP
- X.SH "SEE ALSO"
- Xchmod(1), find(1), ls(1), stat(2)
- X.PP
- XThe C programming language.
- X.SH AUTHOR
- XKen Stauffer (University of Calgary)
- X.PP
- Xstauffer@sixk
- X.SH BUGS
- XThe date operator should also allow for time to be entered.
- XThe date operator can be off by a day, if the
- Xtime on the file is close to midnight.
- END_OF_FILE
- if test 12150 -ne `wc -c <'rh.man'`; then
- echo shar: \"'rh.man'\" unpacked with wrong size!
- fi
- # end of 'rh.man'
- fi
- if test -f 'rhcmds.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'rhcmds.c'\"
- else
- echo shar: Extracting \"'rhcmds.c'\" \(4062 characters\)
- sed "s/^X//" >'rhcmds.c' <<'END_OF_FILE'
- X
- X/* ----------------------------------------------------------------------
- X * FILE: rhcmds.c
- X * VERSION: 2
- X * Written by: Ken Stauffer
- X * This file contains the functions that do the evaluation of
- X * the stack program.
- X * These functions are simple, and behave like RPN operators, that is
- X * they use the last two values on the stack, apply an operator
- X * and push the result. Similarly for unary ops.
- X *
- X * ---------------------------------------------------------------------- */
- X
- X#include "rh.h"
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X
- Xc_or(i) long i; { Stack[SP-2]=Stack[SP-2] || Stack[SP-1]; SP--; }
- Xc_and(i) long i; { Stack[SP-2]=Stack[SP-2] && Stack[SP-1]; SP--; }
- Xc_le(i) long i; { Stack[SP-2]=Stack[SP-2] <= Stack[SP-1]; SP--; }
- Xc_lt(i) long i; { Stack[SP-2]=Stack[SP-2] < Stack[SP-1]; SP--; }
- Xc_ge(i) long i; { Stack[SP-2]=Stack[SP-2] >= Stack[SP-1]; SP--; }
- Xc_gt(i) long i; { Stack[SP-2]=Stack[SP-2] > Stack[SP-1]; SP--; }
- Xc_ne(i) long i; { Stack[SP-2]=Stack[SP-2] != Stack[SP-1]; SP--; }
- Xc_eq(i) long i; { Stack[SP-2]=Stack[SP-2] == Stack[SP-1]; SP--; }
- Xc_bor(i) long i; { Stack[SP-2]=Stack[SP-2] | Stack[SP-1]; SP--; }
- Xc_band(i) long i; { Stack[SP-2]=Stack[SP-2] & Stack[SP-1]; SP--; }
- Xc_bxor(i) long i; { Stack[SP-2]=Stack[SP-2] ^ Stack[SP-1]; SP--; }
- Xc_lshift(i) long i; { Stack[SP-2]=Stack[SP-2] << Stack[SP-1]; SP--; }
- Xc_rshift(i) long i; { Stack[SP-2]=Stack[SP-2] >> Stack[SP-1]; SP--; }
- Xc_plus(i) long i; { Stack[SP-2]=Stack[SP-2] + Stack[SP-1]; SP--; }
- Xc_mul(i) long i; { Stack[SP-2]=Stack[SP-2] * Stack[SP-1]; SP--; }
- Xc_minus(i) long i; { Stack[SP-2]=Stack[SP-2] - Stack[SP-1]; SP--; }
- Xc_div(i) long i; { Stack[SP-2]=Stack[SP-2] / Stack[SP-1]; SP--; }
- Xc_mod(i) long i; { Stack[SP-2]=Stack[SP-2] % Stack[SP-1]; SP--; }
- X
- X
- X/* unary instructions */
- X
- Xc_not(i) long i; { Stack[SP-1] = ! Stack[SP-1]; }
- Xc_bnot(i) long i; { Stack[SP-1] = ~ Stack[SP-1]; }
- Xc_uniminus(i) long i; { Stack[SP-1] = - Stack[SP-1]; }
- X
- X/* trinary operator ?: */
- X
- Xc_qm(i) long i; { PC = (Stack[SP-1]) ? PC : i; SP--; }
- Xc_colon(i) long i; { PC = i; }
- X
- X/* accessing a parameter */
- X
- Xc_param(i)
- Xlong i;
- X{
- X Stack[ SP++ ] = Stack[ FP + i ];
- X}
- X
- X/* calling a function */
- X
- Xc_func(i)
- Xlong i;
- X{
- X Stack[ SP++ ] = PC;
- X Stack[ SP++] = FP;
- X PC = i;
- X FP = SP-(StackProgram[PC].value+2);
- X}
- X
- X/* returning from a function */
- X
- Xc_return(i)
- Xlong i;
- X{
- X PC = Stack[ SP-3 ];
- X FP = Stack[ SP-2 ];
- X Stack[ SP-(3+i) ] = Stack[ SP-1 ];
- X SP -= (2+i);
- X}
- X
- X/* operand functions */
- X
- Xc_number(i) long i; { Stack[SP++] = i; }
- Xc_atime(i) long i; { Stack[SP++] = attr.buf->st_atime; }
- Xc_ctime(i) long i; { Stack[SP++] = attr.buf->st_ctime; }
- Xc_dev(i) long i; { Stack[SP++] = attr.buf->st_dev; }
- Xc_gid(i) long i; { Stack[SP++] = attr.buf->st_gid; }
- Xc_ino(i) long i; { Stack[SP++] = attr.buf->st_ino; }
- Xc_mode(i) long i; { Stack[SP++] = attr.buf->st_mode; }
- Xc_mtime(i) long i; { Stack[SP++] = attr.buf->st_mtime; }
- Xc_nlink(i) long i; { Stack[SP++] = attr.buf->st_nlink; }
- Xc_rdev(i) long i; { Stack[SP++] = attr.buf->st_rdev; }
- Xc_size(i) long i; { Stack[SP++] = attr.buf->st_size; }
- Xc_uid(i) long i; { Stack[SP++] = attr.buf->st_uid; }
- Xc_depth(i) long i; { Stack[SP++] = attr.depth; }
- Xc_prune(i) long i; { Stack[SP++] = 0; attr.prune = 1; }
- X
- X/* calculate the filename length */
- X
- Xc_baselen(i)
- Xlong i;
- X{
- X char *c; register int len;
- X
- X len = 0;
- X for(c=attr.fname; *c; c++ )
- X if( *c == '/' ) len = 0;
- X else len += 1;
- X Stack[SP++] = len;
- X}
- X
- X/* ----------------------------------------------------------------------
- X * c_str:
- X * This implements the regular expression stuff.
- X * 'i' is an index into the array Strbuf[]. The
- X * string contained there is the actual '\0' terminated
- X * string that occured in the expression (eg "*.BAK" ), minus
- X * the quotes "".
- X */
- X
- Xc_str(i)
- Xlong i;
- X{
- X char *tail,*strrchr();
- X
- X tail = strrchr(attr.fname, '/');
- X tail = (tail) ? tail+1 : attr.fname;
- X Stack[SP++] = glob_match(&Strbuf[i], tail, 1);
- X}
- END_OF_FILE
- if test 4062 -ne `wc -c <'rhcmds.c'`; then
- echo shar: \"'rhcmds.c'\" unpacked with wrong size!
- fi
- # end of 'rhcmds.c'
- fi
- if test -f 'rhdata.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'rhdata.c'\"
- else
- echo shar: Extracting \"'rhdata.c'\" \(2739 characters\)
- sed "s/^X//" >'rhdata.c' <<'END_OF_FILE'
- X
- X/* ----------------------------------------------------------------------
- X * FILE: rhdata.c
- X * VERSION: 2
- X * Written by: Ken Stauffer
- X * This file contains the predefined symbol table, and related data
- X * structures.
- X *
- X * ---------------------------------------------------------------------- */
- X
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#define DATA
- X#include "rh.h"
- X
- Xstruct symbol *symbols;
- X
- Xstruct symbol *tokensym;
- Xlong tokenval;
- Xlong token;
- X
- Xchar Strbuf[ STRLEN+1 ];
- Xint strfree=0;
- X
- Xstruct instr StackProgram[ LENGTH ];
- Xint PC;
- Xint startPC;
- X
- Xlong Stack[ MEM+3 ];
- Xint SP;
- Xint FP;
- X
- Xstruct runtime attr;
- X
- X/*
- X * The following variables specify where the input is comming from.
- X * If expstr == NULL then the input is certainly not from there, and
- X * instead is taken from expfile.
- X * else expstr is used as input.
- X *
- X */
- X
- Xchar *expstr;
- XFILE *expfile;
- Xchar *expfname;
- X
- Xstatic struct symbol init_syms[]={
- X { "NOW", NUMBER, 0, c_number, NULL },
- X { "IFBLK", NUMBER, S_IFBLK, c_number, NULL },
- X { "IFCHR", NUMBER, S_IFCHR, c_number, NULL },
- X { "IFDIR", NUMBER, S_IFDIR, c_number, NULL },
- X { "IFMT", NUMBER, S_IFMT, c_number, NULL },
- X { "IFREG", NUMBER, S_IFREG, c_number, NULL },
- X { "ISGID", NUMBER, S_ISGID, c_number, NULL },
- X { "ISUID", NUMBER, S_ISUID, c_number, NULL },
- X { "ISVTX", NUMBER, S_ISVTX, c_number, NULL },
- X#ifdef S_IFLNK
- X { "IFLNK", NUMBER, S_IFLNK, c_number, NULL },
- X#endif
- X#ifdef S_IFSOCK
- X { "IFSOCK", NUMBER, S_IFSOCK, c_number, NULL },
- X#endif
- X#ifdef S_IFIFO
- X { "IFIFO", NUMBER, S_IFIFO, c_number, NULL },
- X#endif
- X { "atime", FIELD, 0, c_atime, NULL },
- X { "ctime", FIELD, 0, c_ctime, NULL },
- X { "dev", FIELD, 0, c_dev, NULL },
- X { "gid", FIELD, 0, c_gid, NULL },
- X { "ino", FIELD, 0, c_ino, NULL },
- X { "mode", FIELD, 0, c_mode, NULL },
- X { "mtime", FIELD, 0, c_mtime, NULL },
- X { "nlink", FIELD, 0, c_nlink, NULL },
- X { "rdev", FIELD, 0, c_rdev, NULL },
- X { "size", FIELD, 0, c_size, NULL },
- X { "uid", FIELD, 0, c_uid, NULL },
- X { "depth", FIELD, 0, c_depth, NULL },
- X { "prune", FIELD, 0, c_prune, NULL },
- X { "days", NUMBER, 24*3600, c_number, NULL },
- X { "weeks", NUMBER, 24*3600*7, c_number, NULL },
- X { "hours", NUMBER, 3600, c_number, NULL },
- X { "strlen", FIELD, 0, c_baselen, NULL },
- X { "return", RETURN, 0, c_return, NULL }
- X};
- X
- Xrhinit()
- X{
- X int i;
- X struct symbol *s,*locatename();
- X
- X symbols = &init_syms[0];
- X
- X for(i=0; i< sizeof(init_syms)/sizeof(struct symbol)-1; i++ )
- X init_syms[i].next = &init_syms[i+1];
- X
- X /* initialize the NOW variable to the time right now */
- X s = locatename( "NOW" );
- X s->value = time(0);
- X}
- X
- Xrhfinish()
- X{
- X struct symbol *s;
- X
- X while(symbols->type == PARAM || symbols->type == FUNCTION) {
- X s = symbols;
- X symbols = symbols->next;
- X free(s->name);
- X free(s);
- X }
- X}
- END_OF_FILE
- if test 2739 -ne `wc -c <'rhdata.c'`; then
- echo shar: \"'rhdata.c'\" unpacked with wrong size!
- fi
- # end of 'rhdata.c'
- fi
- if test -f 'rhdir.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'rhdir.c'\"
- else
- echo shar: Extracting \"'rhdir.c'\" \(6851 characters\)
- sed "s/^X//" >'rhdir.c' <<'END_OF_FILE'
- X
- X/* ----------------------------------------------------------------------
- X * FILE: rhdir.c
- X * VERSION: 2
- X * Written by: Ken Stauffer
- X * This file contains the "non portable" stuff dealing with
- X * directories.
- X * printentry(), ftrw(), fwt1()
- X *
- X *
- X * ---------------------------------------------------------------------- */
- X
- X#include "rh.h"
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X
- X#define user_index(b) ((000777 & (b)) >> 6) + ((b) & S_ISUID ? 8 : 0)
- X#define group_index(b) ((000077 & b) >> 3) + ((b) & S_ISGID ? 8 : 0)
- X#define all_index(b) ((000007 & (b)) + (((b) & S_ISVTX) ? 8 : 0))
- X#define ftype_index(b) ((b) >> 13)
- X
- X#define isdirect(b) (((b)&S_IFMT)==S_IFDIR)
- X#define isblk(b) (((b)&S_IFMT)==S_IFBLK)
- X#define ischr(b) (((b)&S_IFMT)==S_IFCHR)
- X
- X/*
- X * Some System do not define these macro's.
- X * If these macro's are missing, then use these ones:
- X *
- X * #define major(b) ((b)>>8)
- X * #define minor(b) ((b)&0xff)
- X *
- X */
- X
- X#define isdot(s) ((s)[1]=='\0' && (s)[0]=='.')
- X#define isdotdot(s) ((s)[2]=='\0' && (s)[1]=='.' && (s)[0]=='.')
- X
- X#ifdef S_IFLNK
- X#define islink(b) (((b)&S_IFMT) == S_IFLNK)
- X#else
- X#define islink(b) (0)
- X#define lstat stat
- X#endif
- X
- X#define isproper(m) (isdirect(m) && !islink(m) && !attr.prune)
- X
- X#ifdef POSIX_DIRECTORY_LIBRARY
- X#include <dirent.h>
- X#else
- X#include <sys/dir.h>
- X#endif
- X
- X/*
- X * XXX - on BSD systems, this is defined in <sys/param.h>.
- X * On System V Release 3, it's defined inside "nami.c", and is,
- X * unfortunately, not in any include file.
- X * On systems other than those, no such simple limit exists.
- X * On BSD and S5R3 systems, as distributed by Berkeley and AT&T,
- X * respectively, it's 1024, so we set it to that.
- X */
- X#define MAXPATHLEN 1024
- X
- X/* ----------------------------------------------------------------------
- X * printentry:
- X * Display filename,permissions and size in a '/bin/ls' like
- X * format. If verbose is non-zero then more information is
- X * displayed.
- X * uses the macros:
- X * user_index(b)
- X * group_index(b)
- X * all_index(b)
- X * ftype_index(b)
- X *
- X */
- X
- Xprintentry(verbose,buf,name)
- Xstruct stat *buf;
- Xchar *name;
- X{
- X char *t,*ctime();
- X
- X static char *ftype[]={ "p", "c" ,
- X "d" , "b" ,
- X "-" , "l" ,
- X "s" , "t" };
- X
- X static char *perm[]={ "---", "--x", "-w-", "-wx" ,
- X "r--", "r-x", "rw-", "rwx" ,
- X "--S", "--s", "-wS", "-ws" ,
- X "r-S", "r-s", "rwS", "rws" };
- X
- X static char *perm2[]={ "---", "--x", "-w-", "-wx" ,
- X "r--", "r-x", "rw-", "rwx" ,
- X "--T", "--t", "-wT", "-wt" ,
- X "r-T", "r-t", "rwT", "rwt" };
- X
- X if( verbose ) {
- X t = ctime(&buf->st_mtime);
- X t[24] = '\0';
- X if( ischr(buf->st_mode) || isblk(buf->st_mode) )
- X
- X printf("%s%s%s%s %4d %4d %3d,%3d %s %-s\n",
- X ftype[ ftype_index(buf->st_mode) ],
- X perm[ user_index(buf->st_mode) ],
- X perm[ group_index(buf->st_mode) ],
- X perm2[ all_index(buf->st_mode) ],
- X buf->st_uid,
- X buf->st_gid,
- X major(buf->st_rdev),
- X minor(buf->st_rdev),
- X t+4,
- X name );
- X
- X else
- X
- X printf("%s%s%s%s %4d %4d %6d %s %-s\n",
- X ftype[ ftype_index(buf->st_mode) ],
- X perm[ user_index(buf->st_mode) ],
- X perm[ group_index(buf->st_mode) ],
- X perm2[ all_index(buf->st_mode) ],
- X buf->st_uid,
- X buf->st_gid,
- X buf->st_size,
- X t+4,
- X name );
- X
- X } else {
- X
- X if( ischr(buf->st_mode) || isblk(buf->st_mode) )
- X
- X printf("%s%s%s%s %3d,%3d %-s\n",
- X ftype[ ftype_index(buf->st_mode) ],
- X perm[ user_index(buf->st_mode) ],
- X perm[ group_index(buf->st_mode) ],
- X perm2[ all_index(buf->st_mode) ],
- X major(buf->st_rdev),
- X minor(buf->st_rdev),
- X name );
- X
- X else
- X
- X printf("%s%s%s%s %9d %-s\n",
- X ftype[ ftype_index(buf->st_mode) ],
- X perm[ user_index(buf->st_mode) ],
- X perm[ group_index(buf->st_mode) ],
- X perm2[ all_index(buf->st_mode) ],
- X buf->st_size,
- X name );
- X
- X }
- X}
- X
- X/* ----------------------------------------------------------------------
- X * ftrw:
- X * Entry point to do the search, ftrw is a front end
- X * to the recursive fwt1.
- X * ftrw() initializes some global variables and
- X * builds the initial filename string which is passed to
- X * ftw1().
- X */
- X
- Xftrw(f,fn,depth)
- Xchar *f;
- Xint (*fn)();
- Xint depth;
- X{
- X char *p,filebuf[ MAXPATHLEN+1 ];
- X struct stat statbuf;
- X int last;
- X
- X attr.prune = 0;
- X attr.depth = 0;
- X attr.func=fn;
- X attr.fname = filebuf;
- X attr.buf = &statbuf;
- X strcpy(attr.fname,f);
- X
- X last = 0;
- X for(p=attr.fname; *p; p++)
- X if( *p == '/' ) last = 1;
- X else last = 0;
- X
- X if( !last ) { *p++ = '/'; *p = '\0'; }
- X
- X if( lstat(attr.fname,attr.buf) < 0 ) return(-1);
- X
- X (*(attr.func))();
- X
- X if( isproper( attr.buf->st_mode ) ) fwt1(depth,p);
- X
- X return(0);
- X}
- X
- X/* ----------------------------------------------------------------------
- X * fwt1:
- X * 'p' points to the end of the string in attr.fname
- X *
- X * 2 versions of this routine currently live here:
- X * "new-style", for systems with a BSD or POSIX-style
- X * directory library, and systems without such a
- X * directory library. They both differ in
- X * the manner in which they access directories.
- X * Any chnages needed to work on another system
- X * should only have to made for this routine.
- X *
- X * Below is the "directory library" version of fwt1()
- X *
- X */
- X
- X#if defined(POSIX_DIRECTORY_LIBRARY) || defined(BSD)
- X
- Xstatic fwt1(depth,p)
- Xint depth;
- Xchar *p;
- X{
- X char *q,*s;
- X DIR *dirp;
- X#ifdef POSIX_DIRECTORY_LIBRARY
- X struct dirent *dp;
- X#else
- X struct direct *dp;
- X#endif
- X if( !depth ) return;
- X attr.depth += 1;
- X
- X dirp=opendir(attr.fname);
- X if( dirp == NULL ) return;
- X for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
- X if( isdot(dp->d_name) || isdotdot(dp->d_name) ) continue;
- X s = p;
- X q = dp->d_name;
- X while( *s++ = *q++ );
- X s -= 1;
- X if( lstat(attr.fname,attr.buf) < 0 ) continue;
- X (*(attr.func))();
- X if( isproper( attr.buf->st_mode ) ) {
- X *s++ = '/';
- X *s = '\0';
- X fwt1(depth-1,s);
- X }
- X }
- X closedir(dirp);
- X attr.depth -= 1;
- X attr.prune = 0;
- X *p = '\0';
- X}
- X#else
- X
- X/* ----------------------------------------------------------------------
- X * fwt1:
- X * This function does the same thing as fwt1() above, but is
- X * meant for systems without a directory library, that does
- X * directory reading "by hand".
- X *
- X * Below is the "no directory library" version of fwt1()
- X *
- X */
- X
- Xstatic fwt1(depth,p)
- Xint depth;
- Xchar *p;
- X{
- X char *q,*s;
- X FILE *dirp;
- X struct direct dp;
- X int count;
- X
- X if( !depth ) return;
- X attr.depth += 1;
- X
- X dirp=fopen(attr.fname,"r");
- X if( dirp == NULL ) return;
- X for(count = fread(&dp,sizeof(struct direct),1,dirp); count;
- X count = fread(&dp,sizeof(struct direct),1,dirp) ) {
- X
- X if( isdot(dp.d_name) || isdotdot(dp.d_name) || dp.d_ino==0 )
- X continue;
- X s = p;
- X q = dp.d_name;
- X while( *s++ = *q++ );
- X s -= 1;
- X
- X if( lstat(attr.fname,attr.buf) < 0 ) continue;
- X (*(attr.func))();
- X if( isproper( attr.buf->st_mode ) ) {
- X *s++ = '/';
- X *s = '\0';
- X fwt1(depth-1,s);
- X }
- X }
- X fclose(dirp);
- X attr.depth -= 1;
- X attr.prune = 0;
- X *p = '\0';
- X}
- X
- X#endif
- END_OF_FILE
- if test 6851 -ne `wc -c <'rhdir.c'`; then
- echo shar: \"'rhdir.c'\" unpacked with wrong size!
- fi
- # end of 'rhdir.c'
- fi
- if test -f 'rhrc' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'rhrc'\"
- else
- echo shar: Extracting \"'rhrc'\" \(2972 characters\)
- sed "s/^X//" >'rhrc' <<'END_OF_FILE'
- X
- X/* ----------------------------------------------------------------------
- X * FILE: $HOME/.rhrc
- X * VERSION: 2
- X * This file is a sample .rhrc that should live in your home
- X * directory.
- X * The contents of this file are read BEFORE any other input is read
- X * from the user. Functions defined here will be useable elsewhere.
- X *
- X */
- X
- X/*
- X * The dir() function tests a file to see if it is a directory.
- X * The command "rh -e dir", would be enough to find just directories
- X *
- X */
- X
- Xdir()
- X{
- X return( (mode & IFMT) == IFDIR );
- X}
- X
- X/*
- X * months - This function can be used like a constant.
- X * It evaluates to the number of seconds in a month (average).
- X * Expressions like the following are now possible:
- X * (mtime > NOW-2*months)
- X * Would find files that have been modified in the last 2
- X * months.
- X *
- X */
- X
- Xmonths
- X{
- X return days*30;
- X}
- X
- X/*
- X * This defines a useful "alias" for the 'nlink' variable,
- X * which may be easier to remember.
- X *
- X */
- X
- Xnlinks { return nlink; }
- X
- X/*
- X * This function returns the number of seconds passed as its argument
- X * minus NOW. Used to make some time comparisons "cleaner".
- X *
- X */
- X
- Xago(d)
- X{
- X return( NOW - d );
- X}
- X
- X/*
- X * returns true if a file is writable by others (and group).
- X *
- X */
- X
- Xwritable()
- X{
- X return mode & 022;
- X}
- X
- XMINE
- X{
- X return( uid == $$ );
- X}
- X
- X/*
- X * This is my "bad" function which can be easily invoked by the command:
- X * % rh -le bad
- X * This allows me to find files that are not a good idea to have around:
- X * - core files.
- X * - old a.out files.
- X * - files writeable by other people.
- X * - checkpoint and backup files.
- X *
- X */
- X
- Xbad()
- X{
- X return( "core" || ("a.out" && mtime <= ago(2*days) ) ||
- X "*.BAK" || "*.CKP" || writable);
- X}
- X
- X/*
- X * Find C related files.
- X *
- X */
- X
- Xcsrc()
- X{
- X return("*.c" || "*.h" || "[Mm]akefile" );
- X}
- X
- X/*
- X * Find files that have been modified in the last
- X * 1 hour.
- X *
- X */
- X
- Xchanged()
- X{
- X return( mtime > NOW-1*hours );
- X
- X /* ALTERNATELY:
- X * (using the ago() function)
- X *
- X * return( mtime > ago(1*hours) );
- X *
- X */
- X}
- X
- X/*
- X * This function can be used as a constant.
- X *
- X */
- X
- XK()
- X{
- X return 1024;
- X}
- X
- X/* megs { return K*K; } or ...*/
- Xmegs { return K<<10; }
- X
- X/*
- X * This function shows that recursion is quite possible.
- X * Call this function with any number, the higher the number
- X * deeper in recursion it goes. (for large values this function
- X * overflows the stack). This can be used to impose a delay, but that
- X * would be useless on my machine, cause it is sooooo slow already.
- X * Neat mathamatical functions can be calculated this way.
- X *
- X */
- X
- Xrecursion(n)
- X{
- X return (n>0) ? recursion(n-1) : 0;
- X}
- X
- X/*
- X * sqrt(n), returns the integer square root of the number n.
- X * Useful for expressions like:
- X * sqrt(uid) <= gid;
- X * Which finds files where the square root of the user-id is
- X * less than the gid. This one will be used rarely if ever.
- X * sqrt1() is a helper function.
- X *
- X */
- X
- Xsqrt1(n,odd) { return( (n <= 0 ) ? 0 : sqrt1(n-odd,odd+2)+1 ); }
- Xsqrt(n) { return( sqrt1(n,1) ); }
- X
- Xfact(n) { return (n<=0) ? 1 : fact(n-1)*n; }
- END_OF_FILE
- if test 2972 -ne `wc -c <'rhrc'`; then
- echo shar: \"'rhrc'\" unpacked with wrong size!
- fi
- # end of 'rhrc'
- fi
- echo shar: End of archive 1 \(of 2\).
- cp /dev/null ark1isdone
- MISSING=""
- for I in 1 2 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked both archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-